//============================================================================
// Copyright (C) 2013 Brett R. Jones
//
// Issued to public domain 2013
//
// brettjones1900@gmail.com
// http://www.p2panarchy.com
//============================================================================

#include "VxUrl.h"
#include "VxParse.h"
#include "VxSktUtil.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

namespace
{
	const char * PROTOCOL_DELIM = "://";
	const char * USER_DELIM = "@";
	const char * COLON_DELIM = ":";
	const char * SLASH_DELIM = "/";
	const char * POUND_SIGN_DELIM = "#";
	const char * QUESTION_DELIM = "?";
	const char * LEFT_BRACKET_DELIM = "[";
	const char * RIGHT_BRACKET_DELIM = "]";
}

//============================================================================
VxUrl::VxUrl()
{
}

//============================================================================
VxUrl::VxUrl( const char * pUrl )
{
	setUrl( pUrl );
}

//============================================================================
void VxUrl::setUrl( const char * pUrl )
{
	m_strUrl = pUrl;

	// protocol
	int iReadIdx = m_strUrl.find( PROTOCOL_DELIM );
	if( iReadIdx != (int)std::string::npos ) 
	{
		m_strProtocol = m_strUrl.substr( 0, iReadIdx );
		iReadIdx += strlen( PROTOCOL_DELIM );
		StdStringTrim( m_strProtocol );
	}
	else
	{
		iReadIdx = 0;
	}

	// user and password
	int iAtSymbolIdx = m_strUrl.find( USER_DELIM, iReadIdx );
	if( iAtSymbolIdx != (int)std::string::npos ) 
	{
		std::string m_strUserPassStr = m_strUrl.substr( iReadIdx, iAtSymbolIdx - iReadIdx );
		int iColonIdx = m_strUserPassStr.find( COLON_DELIM );
		if( iColonIdx != (int)std::string::npos ) 
		{
			m_strUser = m_strUserPassStr.substr(0, iColonIdx);
			m_strPassword = m_strUserPassStr.substr(iColonIdx + 1, m_strUserPassStr.length() - iColonIdx -1);
		}
		else
		{
			m_strUser = m_strUserPassStr;
		}
		iReadIdx = iAtSymbolIdx + 1;
	}
	// host
	int iSlashIdx = m_strUrl.find( SLASH_DELIM, iReadIdx );
	if( iSlashIdx != (int)std::string::npos )
	{
		m_strHost = m_strUrl.substr(iReadIdx, iSlashIdx - iReadIdx);
	}
	else
	{
		m_strHost = m_strUrl.substr(iReadIdx, m_strUrl.length() - iReadIdx);
	}
	// handle IPv6 and port
	int iColonIdx = m_strHost.rfind( COLON_DELIM );
	int iLeftBracketIdx = m_strHost.rfind( RIGHT_BRACKET_DELIM );
	if (iColonIdx != (int)std::string::npos && iLeftBracketIdx < iColonIdx) 
	{
		std::string strHost = m_strHost;
		m_strHost = strHost.substr( 0, iColonIdx );
		if (0 < m_strHost.length()) 
		{
			if( ( m_strHost.at(0) == '[' ) &&
				 ( m_strHost.at( m_strHost.length() - 1 ) == ']') )
			{
				m_strHost = m_strHost.substr( 1, iColonIdx - 2 );
			}
		}
		std::string m_u16PortStr = strHost.substr(iColonIdx + 1, strHost.length() - iColonIdx -1);
		m_u16Port = atoi(m_u16PortStr.c_str());
	}
	else
	{
		m_u16Port = 80;
	}
	if( iSlashIdx == (int)std::string::npos )
	{
		return;
	}

	iReadIdx = iSlashIdx;

	// path and fragment
	m_strPath = m_strUrl.substr(iReadIdx, m_strUrl.length() - iReadIdx);
	int sharpIdx = m_strPath.find( POUND_SIGN_DELIM );
	if (sharpIdx != (int)std::string::npos) 
	{
		std::string m_strPathStr = m_strPath;
		m_strPath = m_strPathStr.substr(0, sharpIdx);
		m_strFragment = m_strPathStr.substr(sharpIdx + 1, m_strPathStr.length() - sharpIdx -1);
	}
	StdStringTrim( m_strPath );

	int questionIdx = m_strPath.find( QUESTION_DELIM );
	if (questionIdx != (int)std::string::npos) 
	{
		std::string m_strPathStr = m_strPath;
		m_strPath = m_strPathStr.substr(0, questionIdx);
		m_strQuery = m_strPathStr.substr(questionIdx + 1, m_strPathStr.length() - questionIdx -1);
	}
}

//============================================================================
const char * VxUrl::getUrl()
{
	return m_strUrl.c_str();
}

//============================================================================
const char * VxUrl::getProtocol()
{
	return m_strProtocol.c_str();
}

//============================================================================
const char * VxUrl::getUser()
{
	return m_strUser.c_str();
}

//============================================================================
const char * VxUrl::getPassword()
{
	return m_strPassword.c_str();
}

//============================================================================
const char * VxUrl::getHost()
{
	return m_strHost.c_str();
}

//============================================================================
U16 VxUrl::getPort()
{
	return m_u16Port;
}

//============================================================================
const char * VxUrl::getPath()
{
	return m_strPath.c_str();
}

//============================================================================
void VxUrl::setPath( const char * pPathAndFileName )
{
	if( strstr(  pPathAndFileName, "http://" ) )
	{
		setUrl( pPathAndFileName );
	}
	else
	{
		m_strPath = pPathAndFileName;
	}
}

//============================================================================
const char * VxUrl::getQuery()
{
	return m_strQuery.c_str();
}

//============================================================================
const char * VxUrl::getFragment()
{
	return m_strFragment.c_str();
}

//============================================================================
bool VxUrl::isAbsoluteUrl()
{
	return (0 < m_strProtocol.length());
}

//============================================================================
const char * VxUrl::getRelativeURL( std::string& strRetUrl, bool bWithParam )
{
	if( false == isAbsoluteUrl() ) 
	{
		if( (0 < m_strUrl.length()) && 
			( '/' != m_strUrl.at(0) ) )
		{
			strRetUrl = "/";
			strRetUrl += m_strUrl;
		}
	}
	else 
	{
		strRetUrl = getPath();
		if( true == bWithParam ) 
		{
			std::string strQuery = getQuery();
			if( 0 < strQuery.length() )
			{
				strRetUrl += "?";
				strRetUrl += strQuery;
			}
		}
		if( StdStringEndsWith( m_strUrl, "/") ) 
		{
			strRetUrl = m_strUrl.substr( 0, m_strUrl.length() - 1 );
		}
	}
	return strRetUrl.c_str();
}

//============================================================================
const char * VxUrl::getAbsoluteURL( std::string& strRetAbsoluteUrl )
{
	std::string strRelativeUrl;
	std::string strPort;
	strRetAbsoluteUrl = "";
	strRetAbsoluteUrl += getProtocol();
	strRetAbsoluteUrl += PROTOCOL_DELIM;
	strRetAbsoluteUrl += getHost();
	strRetAbsoluteUrl += COLON_DELIM;
	StdStringFormat( strPort, "%d", getPort() );
	strRetAbsoluteUrl += strPort;
	strRetAbsoluteUrl += getRelativeURL(strRelativeUrl);
	return strRetAbsoluteUrl.c_str();
}

//============================================================================
const char * VxUrl::getHostURL( const char * host, int port, const char * uri, std::string& buf )
{
	std::string hostStr = host;
	if( true == VxIsIPv6Address( host ) ) 
	{
		VxStripIPv6ScopeID(host, hostStr);
		hostStr = "[";
		hostStr += hostStr.c_str();
		hostStr += "]";
	}
	std::string portStr;
	buf = "http://";
	buf += hostStr;
	buf += ":";
	buf += StdStringFromInteger( portStr, port );
	buf += uri;
	return buf.c_str();
}
